﻿/*

Copyright (c) 2004-2009 Krzysztof Ostrowski. All rights reserved.

Redistribution and use in source and binary forms,
with or without modification, are permitted provided that the following conditions
are met:

1. Redistributions of source code must retain the above copyright
   notice, this list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above
   copyright notice, this list of conditions and the following
   disclaimer in the documentation and/or other materials provided
   with the distribution.

THIS SOFTWARE IS PROVIDED "AS IS" BY THE ABOVE COPYRIGHT HOLDER(S)
AND ALL OTHER CONTRIBUTORS AND ANY EXPRESS OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDER(S) OR ANY OTHER
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.

*/

using System;
using System.Reflection.Emit;
using System.Collections.Generic;
using System.Threading;
using System.IO;
using System.Net;
using System.Net.Security;
using System.Linq;
using System.ServiceModel;
using System.Reflection;
using System.Text;
using Microsoft.WindowsAzure.Diagnostics;
using Microsoft.WindowsAzure.ServiceRuntime;
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.StorageClient;
namespace QS._qss_x_.Cloud_
{
    public class Worker_ : RoleEntryPoint, QS._qss_x_.Azure_.IAzureWorker_Callback_
    {
        #region Start

        public override bool OnStart()
        {
            #region Connect To Manager

            CloudStorageAccount.SetConfigurationSettingPublisher((configName, configSetter) =>
            {
                configSetter(RoleEnvironment.GetConfigurationSettingValue(configName));
            }
);


            string _deploy_id = Microsoft.WindowsAzure.ServiceRuntime.RoleEnvironment.DeploymentId;

            string _addr = "http://" + _deploy_id+".cloudapp.net/liveobjects_node.svc";
            //string _addr = "http://localhost:82/liveobjects_node.svc";

            BasicHttpBinding _binding = new BasicHttpBinding();
            //_binding.TransferMode = TransferMode.Streamed;
            _binding.MaxReceivedMessageSize = 167108864;
            //_binding.Security.Mode = SecurityMode.None;
            _binding.ReaderQuotas.MaxStringContentLength = 167108864;
            EndpointAddress _endpt = new EndpointAddress(_addr);
            ChannelFactory<liveobjects_node.Iliveobjects_node> cf = new ChannelFactory<liveobjects_node.Iliveobjects_node>(_binding, _endpt);
            liveobjects_node.Iliveobjects_node _web_role = cf.CreateChannel();
            string _web_to_worker_name, _worker_to_web_name;
            _web_role.InitializeQueues(out _web_to_worker_name, out _worker_to_web_name);


            CloudStorageAccount _acct = CloudStorageAccount.FromConfigurationSetting("DiagnosticsConnectionString");
            CloudQueueClient _queue_client = _acct.CreateCloudQueueClient();

            _web_to_worker_q = _queue_client.GetQueueReference(_web_to_worker_name);
            _worker_to_web_q = _queue_client.GetQueueReference(_worker_to_web_name);

            _web_to_worker_q.BeginGetMessage(this.GetMessage_, null);


            ((IClientChannel)_web_role).Close();
            cf.Close();

            #endregion

            // Capture complete crash dumps 
            Microsoft.WindowsAzure.Diagnostics.CrashDumps.EnableCollection(true);

            DiagnosticMonitorConfiguration dmc = DiagnosticMonitor.GetDefaultInitialConfiguration();
            dmc.Logs.ScheduledTransferPeriod = TimeSpan.FromMinutes(1);
            dmc.Logs.ScheduledTransferLogLevelFilter = LogLevel.Verbose;
            
            DiagnosticMonitor.Start("DiagnosticsConnectionString", dmc);
            return base.OnStart();
        }

        System.Runtime.Serialization.Formatters.Binary.BinaryFormatter _bf = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
        liveobjects_node.NodeStatus _status = liveobjects_node.NodeStatus.Unknown;


        private void GetMessage_(IAsyncResult _result)
        {
            CloudQueueMessage _msg = _web_to_worker_q.EndGetMessage(_result);

            if (_msg != null)
            {
                MemoryStream _ms = new MemoryStream(_msg.AsBytes);
                liveobjects_node.Message_ _m = (liveobjects_node.Message_)_bf.Deserialize(_ms);

                _web_to_worker_q.DeleteMessage(_msg);

                switch (_m.Type)
                {
                    case liveobjects_node.MessageType.StatusRequest:
                        liveobjects_node.StatusMessage_ _sm = new liveobjects_node.StatusMessage_(this._status);
                        _ms = new MemoryStream();
                        _bf.Serialize(_ms, _sm);
                        _worker_to_web_q.AddMessage(new CloudQueueMessage(_ms.ToArray()));

                        break;

                    default:
                        throw new Exception("Unexpected message type");
                }
            }

            _web_to_worker_q.BeginGetMessage(this.GetMessage_, null);

            // parse _msg
        }

        Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
        {

            WriteToLog("Error", "AssemblyLoadFailed" + ": " + args.Name);
            return null;
        }


        #endregion

        #region Fields

        string _manager_addr = "localhost:23456";
        CloudQueue _web_to_worker_q, _worker_to_web_q;
        //WorkerStatus_

        #endregion

        #region _Work


        private void WriteToLog(string log_name, string message)
        {
            String roleInstance = RoleEnvironment.CurrentRoleInstance.Id;
            System.Diagnostics.Trace.TraceInformation(log_name + " : " + message);


        }



        public override void Run()
        {
            WriteToLog("Information", "__________Worker._Work : entering");

            #region Create Temp Directory

            System.Diagnostics.ProcessModule mainmodule = System.Diagnostics.Process.GetCurrentProcess().MainModule;
            String mainroot = System.IO.Directory.GetParent(System.IO.Path.GetDirectoryName(mainmodule.FileName)).FullName;
            String temproot = System.IO.Path.Combine(mainroot, @"temp");
            String myid;
            String mytemp;
            do
            {
                DateTime now = System.DateTime.Now;
                Random random = new System.Random();
                myid = now.ToString(@"yyyyMMddHHmmssfffffff") + random.Next(1000000000).ToString(@"000000000");
                mytemp = System.IO.Path.GetFullPath(System.IO.Path.Combine(temproot, myid));
            }
            while (System.IO.Directory.Exists(mytemp));
            System.IO.Directory.CreateDirectory(mytemp);
            System.IO.Directory.SetCurrentDirectory(mytemp);

            #endregion

            #region Initialize Assemblies

            try
            {
                QS._assembly_liveobjects_1._initialize();
                QS._assembly_liveobjects_4._initialize();
                QS._assembly_liveobjects_6._initialize();
                QS._assembly_liveobjects_7._initialize();
                QS._assembly_liveobjects_8._initialize();
                QS._assembly_liveobjects_9._initialize();
            }
            catch (Exception e)
            {
                WriteToLog("Information", e.ToString());
            }

            WriteToLog("Information", "__________Worker._Work : initialized assemblies");

            #endregion

            #region Enumerate Components

            //foreach (QS.Fx.Reflection.IComponentClass _componentclass in
            //        ((QS._qss_x_.Interface_.Classes_.ILibrary2_)QS._qss_x_.Reflection_.Library.LocalLibrary).ComponentClasses())
            //{
            //    try
            //    {
            //        WriteToLog("Information", "__________Worker._Work : component ( " +
            //            ((QS.Fx.Reflection.IClass<QS.Fx.Reflection.IComponentClass>)_componentclass).UnderlyingType.ToString() + " )");
            //    }
            //    catch (Exception e)
            //    {
            //        // Some of these components throw an exception when you try and get their underlying type
            //    }
            //}

            #endregion

            

            //QS.Fx.Object.RuntimeContext _context = new QS.Fx.Object.RuntimeContext(
            //        mytemp, 1, QS.Fx.Object.Runtime.Policy, false);
            //QS.Fx.Object.Runtime.Run(_azuretest_2, _context, new Dictionary<string, string>());

            this._status = liveobjects_node.NodeStatus.Idle;

            WriteToLog("Information", "__________Worker._Work : starting the loop");

            while (true)
            {
                Thread.Sleep(10000);
                //WriteToLog("Information", "__________Worker._Work : running the loop");
            }

            WriteToLog("Information", "__________Worker._Work : leaving");
        }

        #endregion

        

        #region IAzureWorker_Callback_ Members

        void QS._qss_x_.Azure_.IAzureWorker_Callback_.SendStringToClient(string s)
        {
            WriteToLog("Information", "_________IAzureWorker_Callback_ : " + s);
        }

        #endregion
    }
}
